﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

namespace Devonline.Core
{
    public static class AppSettings
    {
        #region 配置文件环境变量
        /// <summary>
        /// 配置文件名
        /// </summary>
        public const string CONFIG_FILE_NAME = "appsettings";
        /// <summary>
        /// 配置文件短名
        /// </summary>
        public const string CONFIG_FILE_SHORT_NAME = "app";
        /// <summary>
        /// 开发环境变量短名
        /// </summary>
        public const string ENVIRONMENT_DEVELOPMENT_SHORT_NAME = "dev";
        /// <summary>
        /// 生产环境变量短名
        /// </summary>
        public const string ENVIRONMENT_PRODUCTION_SHORT_NAME = "pro";
        /// <summary>
        /// 稳定版环境变量短名
        /// </summary>
        public const string ENVIRONMENT_STAGING_SHORT_NAME = "stag";
        /// <summary>
        /// dotnet core 环境变量名称
        /// </summary>
        public const string DOTNETCORE_ENVIRONMENT = "DOTNETCORE_ENVIRONMENT";
        /// <summary>
        /// 日志记录的应用程序名
        /// </summary>
        public const string LOGGING_APPLICATION_NAME = "Application";
        /// <summary>
        /// 日志记录的环境变量名
        /// </summary>
        public const string LOGGING_ENVIRONMENT_NAME = "Environment";
        #endregion

        #region 常用字符定义
        /// <summary>
        /// 符号点, 默认连接符
        /// </summary>
        public const char CHAR_DOT = '.';
        /// <summary>
        /// 逗号
        /// </summary>
        public const char CHAR_COMMA = ',';
        /// <summary>
        /// 空字符
        /// </summary>
        public const char CHAR_EMPTY = '\0';
        /// <summary>
        /// 空格字符
        /// </summary>
        public const char CHAR_SPACE = ' ';
        /// <summary>
        /// 冒号
        /// </summary>
        public const char CHAR_COLON = ':';
        /// <summary>
        /// 分号
        /// </summary>
        public const char CHAR_SEMICOLON = ';';
        /// <summary>
        /// 等于号
        /// </summary>
        public const char CHAR_EQUAL = '=';
        /// <summary>
        /// 横线, 减号, 破折号
        /// </summary>
        public const char CHAR_HLINE = '-';
        /// <summary>
        /// 竖线
        /// </summary>
        public const char CHAR_VLINE = '|';
        /// <summary>
        /// * 号, 通配符
        /// </summary>
        public const char CHAR_STAR = '*';
        /// <summary>
        /// # 符号, 默认注释符号
        /// </summary>
        public const char CHAR_SHARP = '#';
        /// <summary>
        /// 下划线
        /// </summary>
        public const char CHAR_UNDERLINE = '_';
        /// <summary>
        /// 斜杠, 路径分隔符
        /// </summary>
        public const char CHAR_SLASH = '/';
        /// <summary>
        /// 字符 0
        /// </summary>
        public const char CHAR_ZERO = '0';
        /// <summary>
        /// 引号, 默认 sql 语句连接符等
        /// </summary>
        public const char CHAR_QUOTE = '\'';
        /// <summary>
        /// 回车
        /// </summary>
        public const char CHAR_RETURN = '\r';
        /// <summary>
        /// 换行
        /// </summary>
        public const char CHAR_NEW_LINE = '\n';
        /// <summary>
        /// 字符 X, 十六进制格式化符号
        /// </summary>
        public const char CHAR_HEX = 'X';
        /// <summary>
        /// 字符 ?, 问号
        /// </summary>
        public const char CHAR_QUESTION = '?';
        /// <summary>
        /// 字符 &, & 符号
        /// </summary>
        public const char CHAR_ADD = '&';
        /// <summary>
        /// 字符 @, @ 符号
        /// </summary>
        public const char CHAR_AT = '@';
        #endregion

        #region 数学单位定义
        /// <summary>
        /// 数字单位 0
        /// </summary>
        public const int UNIT_ZERO = 0;
        /// <summary>
        /// 数字单位 1
        /// </summary>
        public const int UNIT_ONE = 1;
        /// <summary>
        /// 数字单位 2
        /// </summary>
        public const int UNIT_TWO = 2;
        /// <summary>
        /// 数字单位 4, 2 的 2 次方
        /// </summary>
        public const int UNIT_FOUR = 4;
        /// <summary>
        /// 数字单位 8, 2 的 3 次方
        /// </summary>
        public const int UNIT_EIGHT = 8;
        /// <summary>
        /// 数字单位 16, 2 的 4 次方
        /// </summary>
        public const int UNIT_SIXTEEN = 16;
        /// <summary>
        /// 数字单位 K, 2 的 10 次方
        /// </summary>
        public const int UNIT_KILO = 1024;
        /// <summary>
        /// 数字单位 M, 2 的 20 次方 = 1024 * 1024
        /// </summary>
        public const int UNIT_MEGA = 1_048_576;
        /// <summary>
        /// 数字单位 G, 2 的 30 次方 = 1024 * 1024 * 1024
        /// </summary>
        public const int UNIT_GIGA = 1_073_741_824;
        /// <summary>
        /// 数字单位 T, 2 的 40 次方 = 1024 * 1024 * 1024 * 1024
        /// </summary>
        public const long UNIT_TERA = 1_099_511_627_776;
        /// <summary>
        /// 数字单位 10
        /// </summary>
        public const int UNIT_TEN = 10;
        /// <summary>
        /// 数字单位 100
        /// </summary>
        public const int UNIT_HUNDRED = 100;
        /// <summary>
        /// 数字单位 千
        /// </summary>
        public const int UNIT_THOUSAND = 1_000;
        /// <summary>
        /// 数字单位 百万
        /// </summary>
        public const int UNIT_MILLION = 1_000_000;
        /// <summary>
        /// 数字单位 十亿
        /// </summary>
        public const int UNIT_BILLION = 1_000_000_000;
        /// <summary>
        /// 数字单位 万亿
        /// </summary>
        public const long UNIT_TRILLION = 1_000_000_000_000;
        /// <summary>
        /// 数字单位: 每分钟 60 秒, 同每小时 60 分钟
        /// </summary>
        public const int UNIT_SECONDS_A_MINUTE = 60;
        /// <summary>
        /// 数字单位: 每分钟 60 秒, 同每小时 60 分钟
        /// </summary>
        public const int UNIT_MINUTES_AN_HOUR = UNIT_SECONDS_A_MINUTE;
        /// <summary>
        /// 数字单位: 每天 24 小时
        /// </summary>
        public const int UNIT_HOURS_A_DAY = 24;
        /// <summary>
        /// 数字单位: 每年 12 个月
        /// </summary>
        public const int UNIT_MONTHS_A_YEAR = 12;
        /// <summary>
        /// 数字单位: 每周 7 天, 准确值
        /// </summary>
        public const int UNIT_DAYS_A_WEEK = 7;
        /// <summary>
        /// 数字单位: 每月平均 30 天, 不准确值
        /// </summary>
        public const int UNIT_DAYS_A_MONTH = 30;
        /// <summary>
        /// 数字单位: 每年平均 365 天, 不准确值
        /// </summary>
        public const int UNIT_DAYS_A_YEAR = 365;
        #endregion

        #region 公共常量定义       
        /// <summary>
        /// 默认分页大小
        /// </summary>
        public const int DEFAULT_PAGE_SIZE = 10;
        /// <summary>
        /// 默认页码
        /// </summary>
        public const int DEFAULT_PAGE_INDEX = 1;
        /// <summary>
        /// 二进制默认字符串占位符
        /// </summary>
        public const byte PADDING_CHAR = 0x20;
        /// <summary>
        /// 二进制默认数字占位符
        /// </summary>
        public const byte PADDING_NUMBER = 0x00;
        /// <summary>
        /// 上传出错文件记录目录
        /// </summary>
        public const string ERROR_PATH = "error/";
        /// <summary>
        /// 默认 lambda 表达式变量名
        /// </summary>
        public const string DEFAULT_LAMBDA_PARAMETER = "arg";
        /// <summary>
        /// 默认占位字符串
        /// </summary>
        public const string DEFAULT_SPLITER_STRING = ", ";
        /// <summary>
        /// 默认格式化字符串
        /// </summary>
        public const string DEFAULT_FORMAT_STRING = "{0}";
        /// <summary>
        /// 插件和流程代码中的默认执行方法
        /// </summary>
        public const string DEFAULT_EXECUTE_METHOD = "Execute";
        /// <summary>
        /// 插件和流程代码中的默认异步执行方法
        /// </summary>
        public const string DEFAULT_EXECUTE_ASYNC_METHOD = "ExecuteAsync";
        /// <summary>
        /// 配置文件扩展名
        /// </summary>
        public const string DEFAULT_CONFIG_FILE_EXTENSION = ".json";
        /// <summary>
        /// 日志文件扩展名
        /// </summary>
        public const string DEFAULT_LOG_FILE_EXTENSION = ".log";
        /// <summary>
        /// 程序集文件扩展名
        /// </summary>
        public const string DEFAULT_DLL_FILE_EXTENSION = ".dll";
        /// <summary>
        /// 压缩文件扩展名
        /// </summary>
        public const string DEFAULT_ZIP_FILE_EXTENSION = ".zip";
        /// <summary>
        /// 默认图片文件扩展名
        /// </summary>
        public const string DEFAULT_IMAGE_FILE_EXTENSION = ".jpg";
        /// <summary>
        /// 默认临时文件扩展名
        /// </summary>
        public const string DEFAULT_TEMPORARY_FILE_EXTENSION = ".temp";
        /// <summary>
        /// 默认 Excel 文件扩展名, Excel 07 以上格式
        /// </summary>
        public const string DEFAULT_EXCEL_FILE_EXTENSION = ".xlsx";
        /// <summary>
        /// 默认 Excel xls 文件扩展名
        /// </summary>
        public const string DEFAULT_EXCEL_FILE_EXTENSION_XLS = ".xls";
        /// <summary>
        /// 默认 Excel csv 文件扩展名
        /// </summary>
        public const string DEFAULT_EXCEL_FILE_EXTENSION_CSV = ".csv";
        /// <summary>
        /// 时间格式
        /// </summary>
        public const string DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
        /// <summary>
        /// 中文时间格式
        /// </summary>
        public const string DEFAULT_DATE_FORMAT_CN = "yyyy年MM月dd日";
        /// <summary>
        /// 全时间格式
        /// </summary>
        public const string DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
        /// <summary>
        /// 时间文字格式
        /// </summary>
        public const string DEFAULT_DATETIME_FORMAT_CN = "yyyy年MM月dd日 HH时mm分ss秒";
        /// <summary>
        /// 时间格式的年月部分
        /// </summary>
        public const string DEFAULT_DATEMONTH_FORMAT = "yyyy-MM";
        /// <summary>
        /// 文件中日期格式
        /// </summary>
        public const string DEFAULT_FILE_DATE_FORMAT = "yyyyMMdd";
        /// <summary>
        /// 文件中时间格式
        /// </summary>
        public const string DEFAULT_FILE_DATETIME_FORMAT = "yyyyMMddHHmmss";
        /// <summary>
        /// 默认内容类型
        /// </summary>
        public const string DEFAULT_CONTENT_TYPE = "application/json; charset=utf-8";
        /// <summary>
        /// 默认表单的内容类型
        /// </summary>
        public const string CONTENT_TYPE_OF_FORM = "application/x-www-form-urlencoded";
        /// <summary>
        /// 默认下载的内容类型
        /// </summary>
        public const string CONTENT_TYPE_OF_STREAM = "application/octet-stream";
        /// <summary>
        /// 默认文本编码
        /// </summary>
        public const string DEFAULT_ENCODING = "utf-8";
        /// <summary>
        /// 默认跨域规则名称
        /// </summary>
        public const string DEFAULT_CORS_POLICY = "AllowSpecificOrigins";
        /// <summary>
        /// 不存在
        /// </summary>
        public const string DOES_NOT_EXIST = "doesn't exist";
        /// <summary>
        /// 缓存级别 应用程序缓存
        /// </summary>
        public const string CACHE_APPLICATION = "CACHE_APP_";
        /// <summary>
        /// 缓存级别 数据缓存
        /// </summary>
        public const string CACHE_DATA = "CACHE_DATA_";
        /// <summary>
        /// 缓存级别 用户缓存
        /// </summary>
        public const string CACHE_USER = "CACHE_USER_";
        /// <summary>
        /// 缓存级别 会话缓存
        /// </summary>
        public const string CACHE_SESSION = "CACHE_SESSION_";
        /// <summary>
        /// 系统组, 内置成员账户组
        /// </summary>
        public const string GROUP_SYSTEM = "systems";
        /// <summary>
        /// 授权者
        /// </summary>
        public const string GROUP_AUTHORIZER = "authorizers";
        /// <summary>
        /// 匿名用户组
        /// </summary>
        public const string GROUP_ANONYMOUS = "anonymous";
        /// <summary>
        /// 超级管理员组
        /// </summary>
        public const string GROUP_ADMINISTRATOR = "administrators";
        /// <summary>
        /// 开发人员用户组
        /// </summary>
        public const string GROUP_DEVELOPER = "developers";
        /// <summary>
        /// 维护者用户组, 包含了超级管理员和开发者
        /// </summary>
        public const string GROUP_MAINTAINERS = "administrators, developers";
        /// <summary>
        /// 系统用户
        /// </summary>
        public const string USER_SYSTEM = "system";
        /// <summary>
        /// 匿名用户
        /// </summary>
        public const string USER_ANONYMOUS = "anonymous";
        /// <summary>
        /// 默认超级管理员
        /// </summary>
        public const string USER_ADMINISTRATOR = "administrator";
        /// <summary>
        /// 默认开发者用户
        /// </summary>
        public const string USER_DEVELOPER = "developer";
        #endregion

        #region about file operation
        /// <summary>
        /// 图片文件缩略图默认前缀
        /// </summary>
        public const string DEFAULT_IMAGE_THUMBNAIL_PREFIX = "thumb_";
        /// <summary>
        /// 图片文件缩略图默认尺寸, 宽高像素数, 默认 128
        /// </summary>
        public const int DEFAULT_IMAGE_THUMBNAIL_SIZE = 128;
        /// <summary>
        /// 默认附件集合名称
        /// </summary>
        public const string DEFAULT_ATTACHMENT_NAME = "Attachments";
        /// <summary>
        /// 默认附件路径
        /// </summary>
        public const string DEFAULT_ATTACHMENT_PATH = "Attachments/";
        /// <summary>
        /// 临时文件变量名, 即不记录到数据库的文件设置开关
        /// 这是一个标记, 需要从 http request 中获取该字段的值, 以判断附件是否需要保存
        /// </summary>
        public const string TEMPORARY_ATTACHMENT = nameof(TEMPORARY_ATTACHMENT);
        /// <summary>
        /// 默认支持的可上传文件扩展名
        /// </summary>
        public const string DEFAULT_ALLOW_FILE_EXTENSIONS = ".PNG,.JPG,.JPEG,.GIF,.BMP,.ICO,.XLS,.XLSX,.DOC,.DOCX,.PPT,.PPTX,.PDF,.TXT,.MD,.CSV,.MP3,.WMA,.WAV,.M4A,.MP4,.MKV,.AVI,.MOV,.FLV";
        /// <summary>
        /// 默认单附件文件大小, 为 10MB
        /// </summary>
        public const int DEFAULT_MAX_UPLOAD_FILE_SIZE = UNIT_TEN * UNIT_MEGA;
        /// <summary>
        /// 默认总附件文件大小, 为 100MB
        /// </summary>
        public const int DEFAULT_TOTAL_UPLOAD_FILE_SIZE = UNIT_HUNDRED * UNIT_MEGA;
        /// <summary>
        /// 默认每个表格多少行, 用于导入导出时的单页最大数量
        /// </summary>
        public const int DEFAULT_PAGE_SIZE_OF_ONE_SHEET = UNIT_TEN * UNIT_THOUSAND;
        /// <summary>
        /// 默认下载的 Excel 文件内容类型
        /// </summary>
        public const string CONTENT_TYPE_OF_EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        /// <summary>
        /// 默认下载的 Excel xls 格式文件内容类型
        /// </summary>
        public const string CONTENT_TYPE_OF_EXCEL_XLS = "application/vnd.ms-excel";
        /// <summary>
        /// 默认 excel 列宽
        /// </summary>
        public const int DEFAULT_EXCEL_COLUMN_WIDTH = UNIT_TEN;
        /// <summary>
        /// 默认 excel 序号列列名
        /// </summary>
        public const string DEFAULT_EXCEL_INDEX_FIELD_NAME = "RowIndex";
        /// <summary>
        /// 默认 excel 序号列显示名
        /// </summary>
        public const string DEFAULT_EXCEL_INDEX_COLUMN_NAME = "序号";
        /// <summary>
        /// 默认 excel 字符串类型值格式
        /// </summary>
        public const string DEFAULT_EXCEL_STRING_FORMAT = "@";
        /// <summary>
        /// 默认 excel 整数类型值格式
        /// </summary>
        public const string DEFAULT_EXCEL_NUMBER_FORMAT = "#,##0";
        /// <summary>
        /// 默认 excel 浮点数类型值格式
        /// </summary>
        public const string DEFAULT_EXCEL_DOUBLE_FORMAT = "#,##0.00";
        /// <summary>
        /// 默认 excel 字符串类型值长度
        /// </summary>
        public const float DEFAULT_EXCEL_STRING_SIZE = 30;
        /// <summary>
        /// 默认 excel 整数类型值长度
        /// </summary>
        public const float DEFAULT_EXCEL_NUMBER_SIZE = 10;
        /// <summary>
        /// 默认 excel 浮点数类型值长度
        /// </summary>
        public const float DEFAULT_EXCEL_DOUBLE_SIZE = 15;
        /// <summary>
        /// 默认 excel 时间类型值长度
        /// </summary>
        public const float DEFAULT_EXCEL_DATETIME_SIZE = 20;
        #endregion

        #region about query options
        /// <summary>
        /// count 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_COUNT = "$count";
        /// <summary>
        /// top 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_TOP = "$top";
        /// <summary>
        /// skip 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_SKIP = "$skip";
        /// <summary>
        /// skip 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_FILTER = "$filter";
        /// <summary>
        /// orderby 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_ORDERBY = "$orderby";
        /// <summary>
        /// select 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_SELECT = "$select";
        /// <summary>
        /// expand 查询选项参数名
        /// </summary>
        public const string QUERY_OPTION_EXPAND = "$expand";
        #endregion

        /// <summary>
        /// application startup path
        /// Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        /// </summary>
        public static readonly string StartupPath = AppContext.BaseDirectory;
        /// <summary>
        /// 配置文件名
        /// </summary>
        public static string ConfigFileName { get; private set; }
        /// <summary>
        /// 当前环境配置文件名
        /// </summary>
        public static string EnvironmentConfigFileName { get; private set; }

        /// <summary>
        /// json 全局设置 system.text.json
        /// </summary>
        public static JsonSerializerOptions JsonSerializerOptions { get; private set; }

        /// <summary>
        /// json 全局设置 newtonsoft.json
        /// </summary>
        public static JsonSerializerSettings JsonSerializerSettings { get; private set; }

        /// <summary>
        /// 主配置文件配置
        /// </summary>
        public static IConfiguration Configuration { get; private set; }
        /// <summary>
        /// 配置文件中 AppSetting 的部分, 基础配置
        /// </summary>
        public static AppSetting AppSetting { get; private set; }

        /// <summary>
        /// 静态初始化
        /// </summary>
        private static void Init()
        {
            JsonSerializerSettings = new JsonSerializerSettings
            {
                //使用驼峰样式的key
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                //忽略循环引用
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                TypeNameHandling = TypeNameHandling.None,
                NullValueHandling = NullValueHandling.Ignore,
                //设置时间格式
                DateTimeZoneHandling = DateTimeZoneHandling.Local,
                DateParseHandling = DateParseHandling.DateTime,
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
                //DateFormatString = DEFAULT_DATETIME_FORMAT
            };

            //枚举类型转字符串输出
            JsonSerializerSettings.Converters.Add(new StringEnumConverter());

            // 默认 json 格式化设置
            JsonSerializerOptions = new JsonSerializerOptions
            {
                AllowTrailingCommas = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
                //IgnoreReadOnlyFields = false,
                //IgnoreReadOnlyProperties = false,
                //IncludeFields = false,
                MaxDepth = UNIT_EIGHT,
                NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowNamedFloatingPointLiterals,
                PropertyNameCaseInsensitive = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                ReadCommentHandling = JsonCommentHandling.Skip,
                WriteIndented = true
            };

            // 枚举使用字符串表示形式
            JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
            //// 时间格式使用自定义
            //JsonSerializerOptions.Converters.Add(new DateTimeConverter(DEFAULT_DATETIME_FORMAT));
            //JsonSerializerOptions.Converters.Add(new DateTimeOffsetConverter(DEFAULT_DATETIME_FORMAT));
        }

        /// <summary>
        /// 将 APPSetting 节点配置项添加到依赖注入的容器中
        /// </summary>
        /// <typeparam name="TAppSetting"></typeparam>
        /// <param name="service"></param>
        /// <returns></returns>
        public static TAppSetting AddAppSettings<TAppSetting>(this IServiceCollection services) where TAppSetting : AppSetting, new()
        {
            var configuration = services.BuildServiceProvider().GetService<IConfiguration>();
            Init();

            if (Configuration != configuration)
            {
                //TypeAdapterConfig.GlobalSettings.Default.IgnoreNullValues(true);
                //Configuration = GetConfiguration();
                Configuration = configuration;
            }

            if (Configuration == null)
            {
                throw new Exception("configuration file have not initial!");
            }

            var appSetting = configuration.GetSection(nameof(AppSetting))?.Get<TAppSetting>() ?? new TAppSetting();
            appSetting.Hosts ??= configuration.GetValue<string>(nameof(appSetting.Hosts));
            appSetting.AllowedHosts ??= configuration.GetValue<string>(nameof(appSetting.AllowedHosts));
            appSetting.CorsOrigins ??= configuration.GetValue<string>(nameof(appSetting.CorsOrigins));
            appSetting.IdentityDbContext ??= configuration.GetConnectionString(nameof(appSetting.IdentityDbContext));
            appSetting.ApplicationDbContext ??= configuration.GetConnectionString(nameof(appSetting.ApplicationDbContext));

            AppSetting = appSetting;
            services.AddSingleton(appSetting);
            return appSetting;
        }

        /// <summary>
        /// 主动加载环境相关配置文件
        /// </summary>
        /// <returns></returns>
        public static void UseAppSettings(this IHostBuilder hostBuilder) => hostBuilder.ConfigureAppConfiguration((context, builder) =>
        {
            ConfigFileName = CONFIG_FILE_NAME + DEFAULT_CONFIG_FILE_EXTENSION;
            builder.AddJsonFile(ConfigFileName, optional: false, reloadOnChange: true);
            if (File.Exists(Path.Combine(StartupPath, CONFIG_FILE_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION)))
            {
                ConfigFileName = CONFIG_FILE_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION;
                builder.AddJsonFile(ConfigFileName, optional: false, reloadOnChange: true);
            }

            if (context.HostingEnvironment.IsDevelopment())
            {
                EnvironmentConfigFileName = CONFIG_FILE_NAME + CHAR_DOT + Environments.Development + DEFAULT_CONFIG_FILE_EXTENSION;
                builder.AddJsonFile(EnvironmentConfigFileName, optional: true, reloadOnChange: true);

                if (File.Exists(Path.Combine(StartupPath, CONFIG_FILE_SHORT_NAME + CHAR_DOT + ENVIRONMENT_DEVELOPMENT_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION)))
                {
                    EnvironmentConfigFileName = CONFIG_FILE_SHORT_NAME + CHAR_DOT + ENVIRONMENT_DEVELOPMENT_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION;
                    builder.AddJsonFile(EnvironmentConfigFileName, optional: true, reloadOnChange: true);
                }
            }
            else if (context.HostingEnvironment.IsProduction())
            {
                EnvironmentConfigFileName = CONFIG_FILE_NAME + CHAR_DOT + Environments.Production + DEFAULT_CONFIG_FILE_EXTENSION;
                builder.AddJsonFile(EnvironmentConfigFileName, optional: true, reloadOnChange: true);

                if (File.Exists(Path.Combine(StartupPath, CONFIG_FILE_SHORT_NAME + CHAR_DOT + ENVIRONMENT_PRODUCTION_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION)))
                {
                    EnvironmentConfigFileName = CONFIG_FILE_SHORT_NAME + CHAR_DOT + ENVIRONMENT_PRODUCTION_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION;
                    builder.AddJsonFile(EnvironmentConfigFileName, optional: true, reloadOnChange: true);
                }
            }
            else if (context.HostingEnvironment.IsStaging())
            {
                EnvironmentConfigFileName = CONFIG_FILE_NAME + CHAR_DOT + Environments.Staging + DEFAULT_CONFIG_FILE_EXTENSION;
                builder.AddJsonFile(EnvironmentConfigFileName, optional: true, reloadOnChange: true);

                if (File.Exists(Path.Combine(StartupPath, CONFIG_FILE_SHORT_NAME + CHAR_DOT + ENVIRONMENT_STAGING_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION)))
                {
                    EnvironmentConfigFileName = CONFIG_FILE_SHORT_NAME + CHAR_DOT + ENVIRONMENT_STAGING_SHORT_NAME + DEFAULT_CONFIG_FILE_EXTENSION;
                    builder.AddJsonFile(EnvironmentConfigFileName, optional: true, reloadOnChange: true);
                }
            }

            builder.AddEnvironmentVariables();
        });

        /// <summary>
        /// 提供默认的返回配置文件内容的方式, 如果不指定 section 的值, 则默认返回 AppSetting 节点的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T GetSetting<T>(string key) where T : IConvertible
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            return (key.Contains(CHAR_COLON, StringComparison.CurrentCulture) ? Configuration : Configuration.GetSection(nameof(AppSetting))).GetValue<T>(key);
        }

        /// <summary>
        /// 延迟方法, 时间间隔单位: 秒, 默认 1 秒
        /// </summary>
        /// <param name="interval"></param>
        public static Task Delay(int interval = UNIT_ONE)
        {
            return Task.Delay(interval * UNIT_THOUSAND);
        }

        /// <summary>
        /// 执行长期执行的循环任务, new task need start
        /// </summary>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static Task ExecuteLongRunningLoopTask(Func<bool> exitCondition, Action execute, Func<Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return new Task(async () =>
            {
                while (!exitCondition())
                {
                    try
                    {
                        execute();
                    }
                    catch (Exception ex)
                    {
                        whenException?.Invoke(ex);
                    }
                    finally
                    {
                        if (whenFinally == null)
                        {
                            await Delay().ConfigureAwait(false);
                        }
                        else
                        {
                            await whenFinally().ConfigureAwait(false);
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
        /// <summary>
        /// 执行长期执行的循环任务, new task need start
        /// </summary>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static Task ExecuteLongRunningLoopTask(Func<bool> exitCondition, Func<Task> execute, Func<Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return new Task(async () =>
            {
                while (!exitCondition())
                {
                    try
                    {
                        await execute().ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        whenException?.Invoke(ex);
                    }
                    finally
                    {
                        if (whenFinally == null)
                        {
                            await Delay().ConfigureAwait(false);
                        }
                        else
                        {
                            await whenFinally().ConfigureAwait(false);
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
        /// <summary>
        /// 执行长期执行的循环任务的泛型版本, 使用当前对象作为参数执行长期循环任务, new task need start
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static Task ExecuteLongRunningLoopTask<T>(T t, Func<bool> exitCondition, Func<T, Task> execute, Func<Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return new Task(async () =>
            {
                while (!exitCondition())
                {
                    try
                    {
                        await execute(t).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        whenException?.Invoke(ex);
                    }
                    finally
                    {
                        if (whenFinally == null)
                        {
                            await Delay().ConfigureAwait(false);
                        }
                        else
                        {
                            await whenFinally().ConfigureAwait(false);
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
        /// <summary>
        /// 执行长期执行的循环任务的泛型版本, 使用当前对象作为参数执行长期循环任务, new task need start
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static Task ExecuteLongRunningLoopTask<T>(T t, Func<T, bool> exitCondition, Func<T, Task> execute, Func<T, Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return new Task(async () =>
            {
                while (!exitCondition(t))
                {
                    try
                    {
                        await execute(t).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        whenException?.Invoke(ex);
                    }
                    finally
                    {
                        if (whenFinally == null)
                        {
                            await Delay().ConfigureAwait(false);
                        }
                        else
                        {
                            await whenFinally(t).ConfigureAwait(false);
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
        /// <summary>
        /// 执行批量长期执行的循环任务
        /// </summary>
        /// <param name="parallelCount"></param>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static ParallelLoopResult ExecuteLongRunningLoopParallelTask(int parallelCount, Func<bool> exitCondition, Func<Task> execute, Func<Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return Parallel.For(0, parallelCount, index => ExecuteLongRunningLoopTask(exitCondition, execute, whenFinally, whenException).Start());
        }
        /// <summary>
        /// 执行批量长期执行的循环任务的泛型方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="args"></param>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static ParallelLoopResult ExecuteLongRunningLoopParallelTask<T>(IEnumerable<T> args, Func<bool> exitCondition, Func<T, Task> execute, Func<Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return Parallel.ForEach(args, arg => ExecuteLongRunningLoopTask(arg, exitCondition, execute, whenFinally, whenException).Start());
        }
        /// <summary>
        /// 执行批量长期执行的循环任务的泛型方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="args"></param>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static ParallelLoopResult ExecuteLongRunningLoopParallelTask<T>(IEnumerable<T> args, Func<T, bool> exitCondition, Func<T, Task> execute, Func<T, Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return Parallel.ForEach(args, arg => ExecuteLongRunningLoopTask(arg, exitCondition, execute, whenFinally, whenException).Start());
        }
        /// <summary>
        /// 执行批量长期执行的循环任务的泛型方法, 提供使用 int 类型作为任务数量和编号的参数来启动并行任务
        /// </summary>
        /// <param name="parallelCount"></param>
        /// <param name="exitCondition"></param>
        /// <param name="execute"></param>
        /// <param name="whenFinally"></param>
        /// <param name="whenException"></param>
        /// <returns></returns>
        public static ParallelLoopResult ExecuteLongRunningLoopParallelTask(int parallelCount, Func<int, bool> exitCondition, Func<int, Task> execute, Func<int, Task> whenFinally = null, Action<Exception> whenException = null)
        {
            return Parallel.For(0, parallelCount, index => ExecuteLongRunningLoopTask(index, exitCondition, execute, whenFinally, whenException).Start());
        }
    }
}
